﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SafeScript.MetaModel.Statements
{
    public class IndexOperator : PropertyTailOperator
    {
        public Operator Index;

        public override int GetPrecedence()
        {
            return 20;
        }

        public override ITypeDef ComputeType(ITypeDef goal, bool needsRef, ErrorReport report)
        {
            ITypeDef setType = this.Operator.ComputeType(null, needsRef, report);
            if (setType == null)
                return null;

            ITypeDef indexType = this.Index.ComputeType(null, false, report);
            if (indexType == null)
                return null;

            if ( !(setType is InstanceType))
            {
                report.Add(new ErrorEntry(this.Operator.Node) { Type = ErrorType.NotAnObject });
                return null;
            }
            setType = (setType as InstanceType).Type;
            if (!(indexType is InstanceType))
            {
                report.Add(new ErrorEntry(this.Index.Node) { Type = ErrorType.NotAnObject });
                return null;
            }
            indexType = (indexType as InstanceType).Type;

            if (setType is StringType)
            {
                if (!(indexType is NumericType))
                {
                    report.Add(new ErrorEntry(this.Index.Node) { Type = ErrorType.IncompatibleTypes });
                    return null;
                }
                return new InstanceType() { Type = StringType.Self };
            }

            TemplateInstanceTypeDef templType = setType as TemplateInstanceTypeDef;
            if ( templType == null )
            {
                report.Add(new ErrorEntry(this.Operator.Node) { Type = ErrorType.NotAListOrDict });
                return null;
            }
            if ( !(templType.Template is ListType) && !(templType.Template is DictType))
            {
                report.Add(new ErrorEntry(this.Operator.Node) { Type = ErrorType.NotAListOrDict });
                return null;
            }

            if (templType.Template is ListType)
            {
                if (!(indexType is NumericType))
                {
                    report.Add(new ErrorEntry(this.Index.Node) { Type = ErrorType.IncompatibleTypes });
                    return null;
                }
                ITypeDef targ = templType.TemplateArguments[ListType.Self.TemplateParameters[0]];
                return new InstanceType() { Type = targ };
            }
            else
            {
                if (!(indexType is StringType))
                {
                    report.Add(new ErrorEntry(this.Index.Node) { Type = ErrorType.IncompatibleTypes });
                    return null;
                }
                return new InstanceType() { Type = StringType.Self };
            }
        }
    }
}
